﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;
using System.Windows.Media;
using System.Net;
using System.IO;

namespace KinectWeatherMap
{
    class GifImage : Grid
    {
        #region Fields

        GifBitmapDecoder _decoder;
        Int32Animation _animation;

        WebClient _webClient = new WebClient();

        #endregion

        #region Properties

        #region FrameIndex

        public int FrameIndex
        {
            get { return (int)GetValue(FrameIndexProperty); }
            set { SetValue(FrameIndexProperty, value); }
        }

        public static readonly DependencyProperty FrameIndexProperty =
            DependencyProperty.Register("FrameIndex", typeof(int), typeof(GifImage), new UIPropertyMetadata(0, new PropertyChangedCallback(ChangingFrameIndex)));

        static void ChangingFrameIndex(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
        {
            GifImage gif = obj as GifImage;
            int frame = (int)ev.NewValue;
            for (int i = 0; i < gif.Children.Count; i++)
            {
                if (i <= frame)
                {
                    ((Image)gif.Children[i]).Visibility = Visibility.Visible;
                }
                else
                {
                    ((Image)gif.Children[i]).Visibility = Visibility.Collapsed;
                }
            }
        }

        #endregion

        #region GifSource

        public static readonly DependencyProperty GifSourceProperty = DependencyProperty.Register("GifSource", typeof(Uri), typeof(GifImage), new UIPropertyMetadata(null, new PropertyChangedCallback(GifSourceChanged)));

        public Uri GifSource
        {
            get { return (Uri)GetValue(GifSourceProperty); }
            set { SetValue(GifSourceProperty, value); }
        }

        private static void GifSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
        {
            GifImage gifImage = obj as GifImage;
            gifImage.GifSourceChanged(gifImage.GifSource);
        }

        private void GifSourceChanged(Uri newUri)
        {
            if (_webClient.IsBusy)
            {
                _webClient.CancelAsync();
            }
            
            if (newUri == null)
                return;

            if (newUri.IsFile)
            {
                var bytes = File.ReadAllBytes(newUri.AbsolutePath);
                ProcessGifData(bytes);
            }
            else
            {
                _webClient.DownloadDataAsync(newUri);
            }
        }

        #endregion

        #endregion

        #region Constructors

        public GifImage()
        {
            _webClient.DownloadDataCompleted += new DownloadDataCompletedEventHandler(web_DownloadDataCompleted);
        }

        ~GifImage()
        {
            if (_webClient != null)
            {
                _webClient.Dispose();
            }
        }

        #endregion


        void web_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                //Eat errors silently for now
                return;
            }

            if (_animation != null)
                BeginAnimation(FrameIndexProperty, null);

            ProcessGifData(e.Result);
        }

        private void ProcessGifData(byte[] bytes)
        {
            var stream = new MemoryStream(bytes);
            _decoder = new GifBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
            var firstFrame = _decoder.Frames[0];
            firstFrame.Freeze();

            int count = _decoder.Frames.Count;

            this.Children.Clear();
            for (int i = 0; i < count; i++)
            {
                var image = new Image();
                image.Source = _decoder.Frames[i];
                if (i != 0)
                    image.Visibility = System.Windows.Visibility.Collapsed;

                ushort top = (ushort)((BitmapMetadata)_decoder.Frames[i].Metadata).GetQuery("/imgdesc/Top");
                ushort left = (ushort)((BitmapMetadata)_decoder.Frames[i].Metadata).GetQuery("/imgdesc/Left");
                image.Margin = new Thickness(left, top, 0, 0);
                this.Children.Add(image);
            }

            ushort delay = (ushort)((BitmapMetadata)firstFrame.Metadata).GetQuery("/grctlext/Delay");
            _animation = new Int32Animation(0, count - 1, new Duration(TimeSpan.FromMilliseconds(count * delay * 10)));
            _animation.RepeatBehavior = RepeatBehavior.Forever;
            BeginAnimation(FrameIndexProperty, _animation);
        }

    }
}
